﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CentralAngleTemporaryDimensionHandler.h"
#include "UiViewUtils.h"
#include "IActionManager.h"
#include "IUiView.h"
#include "Vector3dUtils.h"
#include "TemporaryDimensionCommonsUtils.h"
#include "IGraphicsNodeGroup.h"

#include "IUiDocumentViewManager.h"

#include "IModelView.h"
#include "IAction.h"

#include "TemporaryDimensionContext.h"
#include <QLineEdit>
#include <QIntValidator>
#include <QKeyEvent>


#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;

CentralAngleTemporaryDimensionHandler::CentralAngleTemporaryDimensionHandler(gcmp::IUiView* pUIView)
    : TemporaryDimensionHandler(pUIView)
{
}

CentralAngleTemporaryDimensionHandler::~CentralAngleTemporaryDimensionHandler(void)
{
}

bool CentralAngleTemporaryDimensionHandler::event(QEvent* pEvent)
{
    // 此方法应为入口键盘事件的处理函数
    if (pEvent->type() != QEvent::KeyPress)
    {
        return QObject::event(pEvent);
    }

    QKeyEvent* pKeyEvent = dynamic_cast<QKeyEvent*>(pEvent);
    DBG_WARN_AND_RETURN_UNLESS(pKeyEvent != nullptr, QObject::event(pEvent), L"难道pEvent不是键盘事件?",L"GDMPLab",L"2024-03-30");

    // 视图输入的入口
    // 当前Action启用了绘制助手时, 输入数字，激活视图内输入
    // 仅负责启动状态, 不负责状态启动后的事件处理
    if (IsInInputState() == false)
    {
        switch (pKeyEvent->key())
        {
        // 半径输入：
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
            ShowInputWidget(InputState::CentralAngle, false, true, QString::number(pKeyEvent->key() - Qt::Key_0).toStdWString());
            return m_pEditor->event(pEvent);

        case VK_NUMPAD0:
        case VK_NUMPAD1:
        case VK_NUMPAD2:
        case VK_NUMPAD3:
        case VK_NUMPAD4:
        case VK_NUMPAD5:
        case VK_NUMPAD6:
        case VK_NUMPAD7:
        case VK_NUMPAD8:
        case VK_NUMPAD9:
            ShowInputWidget(InputState::CentralAngle, false, true, QString::number(pKeyEvent->key() - VK_NUMPAD0).toStdWString());
            return m_pEditor->event(pEvent);

        case Qt::Key_Minus:
        case VK_SUBTRACT:
        case VK_OEM_MINUS:
            ShowInputWidget(InputState::CentralAngle, false, true, L"-");
            return m_pEditor->event(pEvent);

        default:
            break;
        }
        IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
        IActionManager::RefreshViewInput(pUIView);
    }
    return QObject::event(pEvent);
}

bool CentralAngleTemporaryDimensionHandler::eventFilter(QObject* obj, QEvent* pEvent)
{
    if (pEvent->type() == QEvent::KeyPress)
    {
        QKeyEvent* key_event = dynamic_cast<QKeyEvent*>(pEvent);
        if (key_event)
        {
            IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
            QWidget* pViewWidget = QWidget::find((WId)pUIView->GetUiViewId());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pViewWidget != nullptr, L"pViewWidget指针不能为空",L"GDMPLab",L"2024-03-30");

            switch (key_event->key())
            {

            case Qt::Key_Return:
            case Qt::Key_Enter:
            {
                OnEditorReturnPressed();
                return false;
            }

            case Qt::Key_Escape:
                HideInputWidget();
                return dynamic_cast<QObject*>(pViewWidget)->event(pEvent);

            default:
                break;
            }
        }
    }
    else if (pEvent->type() == QEvent::KeyRelease)
    {
        return true;
    }

    return QObject::eventFilter(obj, pEvent);
}

gcmp::OwnerPtr<gcmp::IGraphicsNodeGroup> CentralAngleTemporaryDimensionHandler::GenerateGraphics(const gcmp::ITemporaryDimensionContext* pCtx)
{
    OwnerPtr<IGraphicsNodeGroup> opGrepGroup = IGraphicsNodeGroup::Create();
    opGrepGroup->SetIsSnappable(false);

    DBG_WARN_AND_RETURN_UNLESS(pCtx, opGrepGroup, L"pCtx为空",L"GDMPLab",L"2024-03-30");
    const CentralAngleTemporaryDimensionContext* pCentralAngleCtx = dynamic_cast<const CentralAngleTemporaryDimensionContext*>(pCtx);
    DBG_WARN_AND_RETURN_UNLESS(pCentralAngleCtx, opGrepGroup, L"pCentralAngleCtx为空",L"GDMPLab",L"2024-03-30");

    Vector3d centerDockPos = pCentralAngleCtx->GetCenterPt();
    Vector3d startDockPos = pCentralAngleCtx->GetStartPt();
    Vector3d endDockPos = pCentralAngleCtx->GetEndPt();
    Vector3d refDockPos = pCentralAngleCtx->GetRefPt();
    Coordinate3d coord = pCentralAngleCtx->GetCoord();
    m_TmpDimStyle.LengthPrecision = pCentralAngleCtx->GetLengthPrecision();
    m_TmpDimStyle.AnglePrecision = pCentralAngleCtx->GetAnglePrecision();
    m_TmpDimStyle.RadiusPrecision = pCentralAngleCtx->GetRadiusPrecision();

    UpdateUiView();
    IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
    IModelView* pModelView = pUIView->GetModelView();
    DBG_WARN_AND_RETURN_UNLESS(pModelView, opGrepGroup, L"pModelView为空！",L"GDMPLab",L"2024-03-30");

    double pixelLength = UiViewUtility::ComputeWorldWidthFromPixel(pUIView, 1);

    if (!(Vector3dUtils::IsEqual(centerDockPos, endDockPos)
        || Vector3dUtils::IsEqual(startDockPos, endDockPos)
        || Vector3dUtils::IsEqual(centerDockPos, startDockPos)))
    {
        OwnerPtr<IGraphicsNodeGroup> opCentralAngleDimensions = TemporaryDimensionCommonsUtils::GenerateCentralAngleDimensionForCenterEndArc(
            centerDockPos, startDockPos, endDockPos, refDockPos, true/*isMinorArc*/, coord,
            m_InputState, m_TmpDimStyle, pixelLength, m_TmpDimData);
        opGrepGroup->AddChild(TransferOwnership(opCentralAngleDimensions));
    }

    OwnerPtr<IGraphicsNodeGroup> opRadiusDimensions = TemporaryDimensionCommonsUtils::GenerateRadiusDimensionForCenterEndArc(
        centerDockPos, startDockPos, startDockPos, true, coord,
        m_InputState, m_TmpDimStyle, pixelLength, m_TmpDimData);
    opGrepGroup->AddChild(TransferOwnership(opRadiusDimensions));

    return opGrepGroup;
}

void CentralAngleTemporaryDimensionHandler::ShowInputWidget(InputState enInputState, bool isTabShift /*= false*/, bool isOverrideValue /*= false*/, std::wstring inputValue/* = L""*/)
{
    bool isInputStateValid = (enInputState == InputState::CentralAngle);
    DBG_WARN_AND_RETURN_VOID_UNLESS(isInputStateValid, L"InputState输入非法!",L"GDMPLab",L"2024-03-30");

    m_InputState = enInputState;

    if (m_InputState != InputState::None)
    {
        // 创建输入框
        if (!isTabShift)
        {
            CreateEditorWidget();
        }

        // 设置文本框过滤器
        QDoubleValidator* pCentralAngleInputValidator = NEW_AS_QT_CHILD(QDoubleValidator, this);
        m_pEditor->setValidator(pCentralAngleInputValidator);
        m_pEditor->setText(QString::fromStdWString(inputValue));

        // 设置输入框位置
        SetEditorPosition(m_TmpDimData.CentralAngleDimensionPosition);

        // 输入合法性检查
        {
            std::unordered_map<const QLineEdit*, const ValidatorBase*> validators;
            validators.insert(std::make_pair(m_pEditor, &m_angValidator));
            m_opValidateHelper->SetValidators(validators);
        }

        // 显示输入框
        m_pEditor->show();
        m_pEditor->setFocus();

        // 刷新当前视图
        IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
        IActionManager::RefreshViewInput(pUIView);
    }
}

bool CentralAngleTemporaryDimensionHandler::WakeOn(int nKeyChar, bool isCtrlPressed /*= false*/, bool isAltPressed /*= false*/, bool isShiftPressed /*= false*/)
{
    // 如果不是数字, 不处理
    if ((nKeyChar < Qt::Key_0 || nKeyChar > Qt::Key_9)
        && (nKeyChar < VK_NUMPAD0 || nKeyChar > VK_NUMPAD9)
        && (nKeyChar != VK_SUBTRACT )
        && (nKeyChar != VK_OEM_MINUS))
    {
        return false;
    }

    Qt::Key key = (Qt::Key)nKeyChar;
    Qt::KeyboardModifiers modifiers = Qt::NoModifier;
    if (isCtrlPressed)
    {
        modifiers |= Qt::ControlModifier;
    }
    if (isAltPressed)
    {
        modifiers |= Qt::AltModifier;
    }
    if (isShiftPressed)
    {
        modifiers |= Qt::ShiftModifier;
    }

    QKeyEvent keyEvent(QEvent::KeyPress, key, modifiers);
    return event(&keyEvent);
}

void CentralAngleTemporaryDimensionHandler::OnEditorReturnPressed()
{
    if (!IsInInputState())
    {
        return;
    }
    
    ActionViewInput inputParam;
    if (m_InputState == InputState::CentralAngle)
    {
        QString centralAngValue = m_pEditor->text();
        double centralAngDigit = centralAngValue.toDouble();
        inputParam.InputType = ActionViewInputType::Confirm_CentralAngle;
        inputParam.InputVal = centralAngDigit;
    }
    else
    {
        DBG_WARN(L"m_InputState怎么不是IS_CentralAngle?",L"GDMPLab",L"2024-03-30");
    }

    // 忽略非法输入
    if (!m_angValidator.ValidateValue(inputParam.InputVal))
    {
        m_pEditor->selectAll();
        return;
    }

    UpdateUiView();
    HideInputWidget();

    // 这个方法会结束当前的IPickPointAction!! 连带结束当前Helper的生命周期!!! 后续不应该再添加任何代码!
    IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
    IActionManager::ProcessViewInput(pUIView, inputParam);
}
